//
//  EMSSkillPlannerSkillBranchView.m
//  EVE Mac Suite
//
//  Created by Vadim Lozko on 4/25/09.
//  Copyright 2009  __Vadim__. All rights reserved.
//

#import "EMSSkillPlannerSkillBranchView.h"
#import "EMSSkillPlannerSkillNodeLayer.h"
#import "EMSSkillPlannerTreeNode.h"
#import "EVEAPICoreDataController.h"
#import "EMSGeneralUtils.h"
#import "EMSSkillTrainingInfo.h"
#import "EVECDCharacter.h"
#import "EVECDSkill.h"
#import "EVECDLearnedSkill.h"

NSInteger depthSort(EMSSkillPlannerTreeNode* num1, EMSSkillPlannerTreeNode* num2, void *context)
{
    if ([num1 treeDepth] < [num2 treeDepth])
        return NSOrderedDescending;
    else if ([num1 treeDepth] > [num2 treeDepth])
        return NSOrderedAscending;
    else
        return NSOrderedSame;
}

@interface EMSSkillPlannerSkillBranchView ()

@property (retain) NSGradient* backgroundGradient;
@property (retain) CALayer* containerLayer;

@end

@interface EMSSkillPlannerSkillBranchView (otherDrawMethods)

-(void)setupBackgroundLayer;

@end



@interface EMSSkillPlannerSkillBranchView (CADrawMethods)

-(EMSSkillPlannerSkillNodeLayer*)drawLayerForLevel:(NSInteger)level withNode:(EMSSkillPlannerTreeNode*)node;
-(EMSSkillPlannerSkillNodeLayer*)recursivelyDrawBranchesFromPath:(NSIndexPath*)path;
-(float)getLevelHeightForLevel:(NSInteger)level;
-(void)setHeight:(float)height forLevel:(NSInteger)level;
-(void)resetLevelHeights;
-(void)incrementHeightsFromLevel:(NSInteger)level byAmount:(float)distance;

@end



@implementation EMSSkillPlannerSkillBranchView

@synthesize backgroundGradient=_backgroundGradient;
@synthesize containerLayer=_containerLayer;

-(id)initWithFrame:(NSRect)frameRect
{
	if(self = [super initWithFrame:frameRect])
	{
		_boundedNodeLayers = [[NSMutableArray alloc] init];
		
	}
	return self;
}

-(void)awakeFromNib
{
	[self resetLevelHeights];
	//[self setupBackgroundLayer];
	self.wantsLayer = YES;
	CALayer* mainLayer = self.layer;
	mainLayer.name = @"mainLayer";
	mainLayer.delegate = self;
	[mainLayer setNeedsDisplay];
	self.containerLayer = [CALayer layer];
	self.containerLayer.name = @"containerLayer";	
	[mainLayer addSublayer:self.containerLayer];
}

-(void)dealloc
{
	[_boundedNodeLayers removeAllObjects];
	[_boundedNodeLayers release];
	[super dealloc];
}

- (void)drawRect:(NSRect)rect {
	
	[self.backgroundGradient drawInRect:self.bounds angle:90.0];
}

#pragma mark Bindings stuff

-(EVECDCharacter*)character
{
	return [windowController character];
}

+(void) initialize
{
    [self exposeBinding:@"contentSet"];
}

- (void)bind:(NSString*)bindingName
    toObject:(id)observableObject
 withKeyPath:(NSString*)observableKeyPath
     options:(NSDictionary*)options
{
    [observableObject addObserver:self
                       forKeyPath:observableKeyPath
                          options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
                          context:nil];
}

-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
	if([[skillTreeTreeController selectedNodes] count])
	{
		id selectedObject = [[[skillTreeTreeController selectedNodes] objectAtIndex:0] representedObject];
		if([[[selectedObject entity] name] isEqualToString:@"EVECDSkill"])
		{
			EVECDSkill* skill = (EVECDSkill*)selectedObject;
			NSPredicate* skillNamePredicate = [NSPredicate predicateWithFormat:@"skill.name like %@", skill.name];
			NSPredicate* characterNamePredicate = [NSPredicate predicateWithFormat:@"partOfLearnedGroup.learnedBy.name like %@", self.character.name];
			NSPredicate* learnedSkillPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:
												  [NSArray arrayWithObjects:skillNamePredicate, characterNamePredicate, nil]];
			EVECDLearnedSkill* learnedSkill = (EVECDLearnedSkill*)[EVECDContext fetchObjectForEntityName:@"EVECDLearnedSkill" 
																						   withPredicate:learnedSkillPredicate];
			if(skillBranchNodes)
			{
				[skillBranchNodes release];
			}
			skillBranchNodes = [[EMSSkillTrainingInfo generateTreeForSkill:learnedSkill level:1] retain];
			[self resetLevelHeights];
			[CATransaction begin];
			if([_boundedNodeLayers count] > 0)
			{
				[_boundedNodeLayers makeObjectsPerformSelector:@selector(unbind:) withObject:@"value"];
				[_boundedNodeLayers removeAllObjects];
			}
			//With GC
			//[self.containerLayer setSublayers:[NSArray array]];
			//NO GC
			[self.containerLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
			[self recursivelyDrawBranchesFromPath:[skillBranchNodes indexPath]];
			[CATransaction commit];	
		} else {
			if(skillBranchNodes)
			{
				[skillBranchNodes release];
				skillBranchNodes = nil;
			}
		}
	}
}

@end

@implementation EMSSkillPlannerSkillBranchView (CADrawMethods)

-(EMSSkillPlannerSkillNodeLayer*)drawLayerForLevel:(NSInteger)level withNode:(EMSSkillPlannerTreeNode*)node;
{
	EMSSkillPlannerSkillNodeLayer* nodeLayer = [EMSSkillPlannerSkillNodeLayer nodeLayerWithRepresentation:node];
	nodeLayer.delegate = self;
	CGFloat x = self.containerLayer.frame.origin.x + ((level - 1) * BOX_WITH_SPACING_WIDTH) + LEFT_OFFSET;
	CGFloat y = self.layer.frame.size.height - [self getLevelHeightForLevel:level];
	nodeLayer.position = CGPointMake(x, y);
	if(node.learnedSkill.currentlyInTraining.boolValue)
	{
		[nodeLayer bind:@"value" toObject:node.learnedSkill withKeyPath:@"skillPointsLearned" options:nil];
		[_boundedNodeLayers addObject:nodeLayer];
	}
	
	[self.containerLayer addSublayer:nodeLayer];
	return nodeLayer;
}

-(EMSSkillPlannerSkillNodeLayer*)recursivelyDrawBranchesFromPath:(NSIndexPath*)path
{
	EMSSkillPlannerTreeNode* node = (EMSSkillPlannerTreeNode*)[skillBranchNodes descendantNodeAtIndexPath:path];
	NSUInteger level;
	if(!node) //Root node
	{
		node = skillBranchNodes;
		level = 1;
	} else {
		level = [path length] + 1;
	}	
	if([node isLeaf])
	{
		EMSSkillPlannerSkillNodeLayer* drawnNode = [self drawLayerForLevel:level withNode:node];
		[self incrementHeightsFromLevel:level byAmount:BOX_WITH_SPACING_HEIGHT];
		return drawnNode;
		
	} else {
		NSArray* childNodes = [[node childNodes] sortedArrayUsingFunction:depthSort context:NULL];
		NSMutableArray* drawnChildLayers = [NSMutableArray array];
		for(EMSSkillPlannerTreeNode* childNode in childNodes)
		{
			[drawnChildLayers addObject:[self recursivelyDrawBranchesFromPath:[childNode indexPath]]];
		}
		EMSSkillPlannerSkillNodeLayer* firstChildLayer = [drawnChildLayers objectAtIndex:0];
		EMSSkillPlannerSkillNodeLayer* lastChildLayer = [drawnChildLayers lastObject];
		CGFloat firstChildMidY = CGRectGetMidY(firstChildLayer.frame);
		CGFloat lastChildMidY = CGRectGetMidY(lastChildLayer.frame);
		CGFloat incrementToMidAmount = (((firstChildMidY - lastChildMidY) / 2));
		[self setHeight:(self.layer.frame.size.height - firstChildMidY) forLevel:level];
		[self incrementHeightsFromLevel:level byAmount:incrementToMidAmount];
		EMSSkillPlannerSkillNodeLayer* drawnNode = [self drawLayerForLevel:level withNode:node];
		[self incrementHeightsFromLevel:level byAmount:/*incrementToMidAmount + */BOX_WITH_SPACING_HEIGHT];
		
		CGFloat drawnNodeMidX = CGRectGetMidX(drawnNode.frame);
		CGFloat drawnNodeMidY = CGRectGetMidY(drawnNode.frame);
		for(EMSSkillPlannerSkillNodeLayer* drawnChildLayer in drawnChildLayers)
		{
			drawnChildLayer.parentNodeLayer = drawnNode;
			CGFloat drawnChildNodeMidX = CGRectGetMidX(drawnChildLayer.frame);
			CGFloat drawnChildNodeMidY = CGRectGetMidY(drawnChildLayer.frame);
			CGFloat xDistance = drawnChildNodeMidX - drawnNodeMidX;
			CGFloat yDistance = drawnChildNodeMidY - drawnNodeMidY;
			CGFloat diagnalDistance = hypot(xDistance, yDistance);
			CGFloat angle = atan(yDistance / xDistance);
			CALayer* lineLayer = [CALayer layer];
			lineLayer.backgroundColor = CGColorCreateGenericRGB(0.0, 0.0, 0.0, 1.0);
			lineLayer.bounds = CGRectMake(0.0, 0.0, diagnalDistance, 5);
			lineLayer.anchorPoint = CGPointMake(0.0, 0.0);
			lineLayer.position = CGPointMake(drawnNodeMidX, drawnNodeMidY);
			CATransform3D rotationTransform = CATransform3DMakeRotation(angle, 0.0 , 0.0 , 1.0);
			lineLayer.transform = rotationTransform;
			[self.containerLayer insertSublayer:lineLayer atIndex:0];
		}
		return drawnNode;
	}
}

-(float)getLevelHeightForLevel:(NSInteger)level
{
	switch (level) {
		case 1:
			return level1Height;
		case 2:
			return level2Height;
		case 3:
			return level3Height;
		case 4:
			return level4Height;
		case 5:
			return level5Height;
	}
	return 0.0;
}

-(void)setHeight:(float)height forLevel:(NSInteger)level
{
	switch (level) {
		case 1:
			level1Height = height;
			break;
		case 2:
			level2Height = height;
			break;
		case 3:
			level3Height = height;
			break;
		case 4:
			level4Height = height;
			break;
		case 5:
			level5Height = height;
			break;
		default:
			break;
	}
}

-(void)resetLevelHeights
{
	level1Height = 50.0;
	level2Height = 50.0;
	level3Height = 50.0;
	level4Height = 50.0;
	level5Height = 50.0;
}

-(void)incrementHeightsFromLevel:(NSInteger)level byAmount:(float)distance
{
	switch (level) {
		case 1:
			level1Height += distance;
			[self incrementHeightsFromLevel:2 byAmount:0];
			break;
		case 2:
			level2Height += distance;
			if(level2Height < level1Height) level2Height = level1Height;
			[self incrementHeightsFromLevel:3 byAmount:0];
			break;
		case 3:
			level3Height += distance;
			if(level3Height < level2Height) level3Height = level2Height;
			[self incrementHeightsFromLevel:4 byAmount:0];
			break;
		case 4:
			level4Height += distance;
			if(level4Height < level3Height) level4Height = level3Height;
			[self incrementHeightsFromLevel:5 byAmount:0];
			break;
		case 5:
			if(level5Height < level4Height) level5Height = level4Height;
			level5Height += distance;
		default:
			break;
	}
}

-(BOOL)isFlipped
{
	return YES;
}

@end

@implementation EMSSkillPlannerSkillBranchView (otherDrawMethods)

-(void)setupBackgroundLayer
{
	CGFloat red1   =    0.0 / 255.0;
    CGFloat green1 =   72.0 / 255.0;
    CGFloat blue1  =  127.0 / 255.0;
	
    CGFloat red2    =   0.0 / 255.0;
    CGFloat green2  =  43.0 / 255.0;
    CGFloat blue2   =  76.0 / 255.0;
	
    NSColor* gradientTop    = [NSColor colorWithCalibratedRed:red1 green:green1 blue:blue1 alpha:1.0];    
    NSColor* gradientBottom = [NSColor colorWithCalibratedRed:red2 green:green2 blue:blue2 alpha:1.0];
	
    NSGradient* gradient;
    gradient = [[NSGradient alloc] initWithStartingColor:gradientBottom endingColor:gradientTop];
	
    self.backgroundGradient = gradient;
    [gradient release];
}

@end

